"""
wow.apis.character
==================

The classes representing characters in the Armory, both fully and
partially loaded versions.

"""

import datetime
import time

from wow.core import ArmoryInterface, BasicContainer, RecursionContainer, replace_keys
from wow.exceptions import *

class Character(ArmoryInterface):
    """
    Character
    =========
    
    A class representing a partially-loaded character, such as when
    using the results from a character search or a guild roster
    listing.
    
    If the ``Character`` instance is bound to a ``wow.API`` ditto, 
    it can be upgraded to a ``FullCharacter`` through the method
    ``load_full``.
      
    """
    has_sheet = False
    has_reputation = False
    has_skills = False
    has_talents = False
    has_arena_teams = False
    def __init__(self, attrs, api=None, region=None):
        """
        Character.__init__(attrs, api=None, region=None) -> Character
        Initialise the class, storing all applicable attributes.
        
        todo: support for guild ranks
        
        """
        ArmoryInterface.__init__(self, api, region)
        self.set_attributes(attrs)

    def __repr__(self):
        """
        __repr__(self) -> str
        Return a textual representation of the character instance.
        
        """
        return '<Character %s (%s-%s)>' % (self.name, self.region.upper(), self.realm)

    def set_attributes(self, attrs):
        """
        set_attributes(self, attrs) -> None
        Set a bunch of attributes about the character.
        
        """
        self.name = attrs.get('name')
        self.level = int(attrs.get('level', 0)) or None
        self.klass = attrs.get('class')
        self.klass_id = self.klass and int(attrs.get('classId')) or None
        self.race = attrs.get('race')
        self.race_id = self.race and int(attrs.get('raceId')) or None
        self.gender = attrs.get('gender')
        self.gender_id = self.gender and int(attrs.get('genderId')) or None
        self.guild = attrs.get('guild') or attrs.get('guildName')
        self.guild_id = self.guild and attrs.get('guildId') or None
        self.realm = attrs.get('realm')
        self.battlegroup = attrs.get('battleGroup')
        self.battlegroup_id = self.battlegroup and int(attrs.get('battleGroupId', 0)) or None
        self.relevance = attrs.get('relevance')
        self.search_rank = attrs.get('searchRank')
        self.last_login_raw = attrs.get('lastLoginDate')
        self.last_login_date = self.last_login_raw and datetime.datetime(*time.strptime(self.last_login_raw[:-2], '%Y-%m-%d %H:%M:%S')[:6]) or None

    def load_sheet(self):
        """
        load_sheet(self) -> None
        Retrieve the information found in the character sheet,
        including it in the instance.
        
        """
        self.assert_api('load_sheet')
        
        tree = self.api.retrieve_data(self.region, 'character-sheet', {'r': self.realm, 'n': self.name})
        assert tree.characterInfo._dir, CharNotFound(self.name)
        
        char = tree.characterInfo.character
        self.set_attributes(char._attrs)
        
        tab = tree.characterInfo.characterTab
        self.buffs = Auras(tab.buffs._dir)
        self.debuffs = Auras(tab.debuffs._dir)
        self.talent_spec = TalentSpec(tab.talentSpec)
        self.pvp = RecursionContainer(tab.pvp)
        
        skill1, skill2 = tab.professions._dir
        self.skills = BasicContainer({
            skill1('key').encode(): BasicContainer(value=int(skill1('value')), max=int(skill1('max'))),
            skill2('key').encode(): BasicContainer(value=int(skill2('value')), max=int(skill2('max')))
        })  # temporary
        
        self.title = tab.title('value')
        self.known_titles = Titles(tab.knownTitles, self.title)
        self.character_bars = RecursionContainer(tab.characterBars)
        self.base_stats = RecursionContainer(tab.baseStats)
        self.resistances = RecursionContainer(tab.resistances)
        self.melee = RecursionContainer(tab.melee)
        self.ranged = RecursionContainer(tab.ranged)
        self.spell = RecursionContainer(tab.spell)
        self.defenses = RecursionContainer(tab.defenses)
        
        self.has_sheet = True

class Auras(list):
    """
    Auras
    =====
    
    A list of buffs/debuffs.
    
    """
    def __init__(self, elements):
        """
        Auras.__init__(self, elements) -> Auras
        
        """
        self += [BasicContainer(aura._attrs) for aura in elements]

class TalentSpec(list):
    """
    TalentSpec
    ==========
    
    A talent spec listing (very basic currently).

    todo: extend greatly.
    
    """
    def __init__(self, spec):
        """
        TalentSpec.__init__(self, spec) -> TalentSpec
        
        """
        self += [int(spec('treeOne')), int(spec('treeTwo')), int(spec('treeThree'))]
        self.tree_one, self.tree_two, self.tree_three = self

class PvpInfo(BasicContainer):
    """
    PvpInfo
    =======
    
    A container for various PvP statistics (lifetime honorable
    kills, arena currency).
    
    todo: build arena teams into this class (not Armory-compliant,
    but too logical to pass up on)
    
    """
    def __init__(self, element):
        """
        PvpInfo.__init__(self, element) -> PvpInfo
        
        """
        self['lifetime_honorable_kills'] = element.lifetimehonorablekills('value')
        self['arena_currency'] = element.arenacurrency('value')

class Titles(list):
    """
    Titles
    ======
    
    An object containing all of a character's known titles.
    
    """
    def __init__(self, element, current_title):
        """
        Titles.__init__(self, element, current_title) -> Titles
        
        """
        self += [title('value') for title in element._dir]
        self.current = current_title
